import base64, hashlib, json, os, time
from email import utils
from urllib import parse
from .abstract import ContentRecognizer
from .. import constants, hmacSha256
# 印刷文字识别接口地址
OCRURL = 'https://webapi.xfyun.cn/v1/service/v1/ocr/general'
# 手写文字识别接口地址
HANDWRITINGOCRURL = 'https://webapi.xfyun.cn/v1/service/v1/ocr/handwriting'
# 物体识别接口地址
CURRENCYURL = 'http://tupapi.xfyun.cn/v1/currency'
# 场景识别接口地址
SCENEURL = 'http://tupapi.xfyun.cn/v1/scene'
# 场所识别接口地址
PLACEURL = 'https://api.xf-yun.com/v1/private/s5833e7f6'
# 通用文字识别接口地址
PUBLICOCRURL = 'https://api.xf-yun.com/v1/private/sf8e6aca1'
# 应用ID
APPID = '1b24b601'
def getHeaders(apiKey, **params):
    #当前时间戳
    curTime = str(int(time.time()))
    paramBase64 = base64.b64encode(json.dumps(params).encode())
    m2 = hashlib.md5()
    str1 = apiKey + curTime + paramBase64.decode()
    m2.update(str1.encode())
    checkSum = m2.hexdigest()
    #组装http请求头
    return {
      'X-CurTime': curTime,
      'X-Param': paramBase64.decode(),
      'X-Appid': APPID,
      'X-CheckSum': checkSum,
      'Content-Type': f'application/x-www-form-urlencoded; charset={constants.CHARSET}'
    }
def getUrlAndHeaders(baseUrl, apiSecret, apiKey):
    uri = parse.urlparse(baseUrl)
    host, path = uri.netloc, uri.path
    date = utils.formatdate(timeval = time.time(), localtime = False, usegmt = True)
    signatureOrigin = f'host: {host}\ndate: {date}\nPOST {path} HTTP/1.1'
    signatureSha = hmacSha256.HMACSha256(apiSecret.encode(), signatureOrigin.encode()).digest()
    signature = base64.b64encode(signatureSha).decode()
    authorizationOrigin = f'api_key="{apiKey}", algorithm="hmac-sha256", headers="host date request-line", signature="{signature}"'
    authorization = base64.b64encode(authorizationOrigin.encode()).decode()
    params = {
        "host": host,
        "date": date,
        "authorization": authorization
    }
    url = baseUrl + '?' + parse.urlencode(params)
    headers = {
      'Content-Type': "application/json",
      'Host': host,
      'app_id': APPID
    }
    return url, headers
# 基本识别器类
class BaseRecognizer(ContentRecognizer):
    def onCancel(self):pass
    # 读取标签文件
    def getLabelName(self, filename, label):
        selfDir = os.path.dirname(__file__)
        with open(os.path.join(selfDir, filename), 'r', encoding = constants.CHARSET) as f:
            for line in f.readlines():
                fields = line.strip().split('\t')
                if fields[0].startswith('#'):continue
                if fields[0] == str(label):
                    return fields
#OCR识别器类
class OcrRecognizer(BaseRecognizer):
    #识别接口
    def onRecog(self, imgData):
        #imgData: 带有文件头部信息的二进制位图数据
        headers = getHeaders('121f2ab9d6955aea9e966acdae571260', language = 'cn|en', location = 'true')
        imgBase64Data=base64.b64encode(imgData)
        data='image=%s' % imgBase64Data.decode()
        res = self.post(OCRURL, data.encode(), headers)
        if int(res['code'])!=0:
            raise Exception(res['desc'])
        data=res['data']
        if not data:
            raise Exception('No data.')
        block=data['block']
        if not block:
            raise Exception('No block.')
        for item in block:
            if not item or item['type']!='text':continue
            lines=[]
            for line in item['line']:
                if not line:continue
                words=[]
                for word in line['word']:
                    if not word:continue
                    location=word['location']
                    topLeft=location['top_left']
                    rightBottom=location['right_bottom']
                    words.append({'x':topLeft['x'], 'y':topLeft['y'], 'width':(rightBottom['x'] -topLeft['x']), 'height':(rightBottom['y'] -rightBottom['y']), 'text':word['content']})
                lines.append(words)
        return lines
#手写OCR识别器类
class HandwritingOcrRecognizer(BaseRecognizer):
    #识别接口
    def onRecog(self, imgData):
        #imgData: 带有文件头部信息的二进制位图数据
        headers = getHeaders('121f2ab9d6955aea9e966acdae571260', language = 'cn|en', location = 'true')
        imgBase64Data=base64.b64encode(imgData)
        data='image=%s' % imgBase64Data.decode()
        res = self.post(HANDWRITINGOCRURL, data.encode(), headers)
        if int(res['code'])!=0:
            raise Exception(res['desc'])
        data=res['data']
        if not data:
            raise Exception('No data.')
        block=data['block']
        if not block:
            raise Exception('No block.')
        for item in block:
            if not item or item['type']!='text':continue
            lines=[]
            for line in item['line']:
                if not line:continue
                location = line['location']
                topLeft = location['top_left']
                rightBottom = location['right_bottom']
                content = ' '.join([word['content'] for word in line['word']])
                lines.append([{'x':topLeft['x'], 'y':topLeft['y'], 'width':(rightBottom['x'] -topLeft['x']), 'height':(rightBottom['y'] -rightBottom['y']), 'text': content}])
        return lines
# 物体识别器类
class CurrencyRecognizer(BaseRecognizer):
    #识别接口
    def onRecog(self, imgData):
        #imgData: 带有文件头部信息的二进制位图数据
        headers = getHeaders('e5e633137523ef319602a239bb9b6bd1', image_name = 'img.bmp')
        res = self.post(CURRENCYURL, imgData, headers)
        print(res)
        if int(res['code'])!=0:
            raise Exception(res['desc'])
        data=res['data']
        if not 'fileList' in data.keys():
            raise Exception('No result.')
        lines = []
        for file in data['fileList']:
            try:
                label, enName, cnName, category = self.getLabelName('currency.txt', file['label'])
                lines.append([{'x':0, 'y':0, 'width':0, 'height':0, 'text': f'{category}： {cnName}({enName})'}])
            except ValueError:
                label, enName, cnName = self.getLabelName(file['label'])
                lines.append([{'x':0, 'y':0, 'width':0, 'height':0, 'text': f'{cnName}({enName})'}])
        return lines
# 场景识别器类
class SceneRecognizer(BaseRecognizer):
    #识别接口
    def onRecog(self, imgData):
        #imgData: 带有文件头部信息的二进制位图数据
        headers = getHeaders('e5e633137523ef319602a239bb9b6bd1', image_name = 'img.bmp')
        res = self.post(SCENEURL, imgData, headers)
        print(res)
        if int(res['code'])!=0:
            raise Exception(res['desc'])
        data=res['data']
        if not 'fileList' in data.keys():
            raise Exception('No result.')
        lines = []
        for file in data['fileList']:
            label, name = self.getLabelName('scene.txt', file['label'])
            lines.append([{'x':0, 'y':0, 'width':0, 'height':0, 'text': name}])
        return lines
# 场所识别器类
class PlaceRecognizer(BaseRecognizer):
    #识别接口
    def onRecog(self, imgData):
        #imgData: 带有文件头部信息的二进制位图数据
        apiSecret = 'NTdkMzYzMTk4OTU0N2QzYzkwMGM3NWY5'
        apiKey = 'e8f12c7e96ed86ca5f56ebc2c23cf388'
        data = {
          "header": {
            "app_id": APPID,
            "status": 3
          },
          "parameter": {
            "s5833e7f6": {
              "func": "image/place",
              "result": {
                "encoding": "utf8",
                "compress": "raw",
                "format": "json"
              }
            }
          },
          "payload": {
            "data1": {
              "encoding": "bmp",
              "status": 3,
              "image": base64.b64encode(imgData).decode()
            },
          }
        }
        url, headers = getUrlAndHeaders(PLACEURL, apiSecret, apiKey)
        res = self.post(url, json.dumps(data).encode(), headers)
        if not 'header' in res.keys():
            raise Exception(_('Bad response, bacause no header.'))
        header = res['header']
        if int(header['code']) != 0:
            raise Exception(header['message'])
        payload = res['payload']
        if not 'result' in payload.keys():
            raise Exception(_('No result in payload.'))
        result = payload['result']
        text = base64.b64decode(result['text']).decode()
        data = json.loads(text)
        if not data:
            raise Exception(_('No data in result.'))
        lines = []
        for place in data['place']:
            words = []
            for entity in place['entity']:
                label, name = self.getLabelName('place.txt', entity['id'])
                words.append({'x':0, 'y':0, 'width':0, 'height':0, 'text': name})
            lines.append(words)
        return lines
# 通用 OCR 识别器类
class PublicOcrRecognizer(BaseRecognizer):
    #识别接口
    def onRecog(self, imgData):
        #imgData: 带有文件头部信息的二进制位图数据
        apiSecret = 'NTdkMzYzMTk4OTU0N2QzYzkwMGM3NWY5'
        apiKey = 'e8f12c7e96ed86ca5f56ebc2c23cf388'
        data = {
          "header": {
            "app_id": APPID,
            "status": 3
          },
          "parameter": {
            "sf8e6aca1": {
              "category": "ch_en_public_cloud",
              "result": {
                "encoding": "utf8",
                "compress": "raw",
                "format": "json"
              }
            }
          },
          "payload": {
            "sf8e6aca1_data_1": {
              "encoding": "bmp",
              "status": 3,
              "image": base64.b64encode(imgData).decode()
            }
          }
        }
        url, headers = getUrlAndHeaders(PUBLICOCRURL, apiSecret, apiKey)
        res = self.post(url, json.dumps(data).encode(), headers)
        if not 'header' in res.keys():
            raise Exception(_('Bad response, bacause no header.'))
        header = res['header']
        if int(header['code']) != 0:
            raise Exception(header['message'])
        payload = res['payload']
        if not 'result' in payload.keys():
            raise Exception(_('No result in payload.'))
        result = payload['result']
        text = base64.b64decode(result['text']).decode()
        data = json.loads(text)
        if not data:
            raise Exception(_('No data in result.'))
        lines = []
        for page in data['pages']:
            if not 'lines' in page.keys():
                lines.append([{'x': 0, 'y': 0, 'width': page['width'], 'height': page['height'], 'text': '空白图形'}])
                continue
            for i, pageLine in enumerate(page['lines']):
                words = []
                if pageLine['exception'] != 0 or not 'words' in pageLine.keys():
                    a, b, c, d = pageLine['coord']
                    words.append({'x': a['x'], 'y': a['y'], 'width': b['x'] -a['x'], 'height': d['y'] -a['y'], 'text': f'图形{i + 1}'})
                else:
                    for word in pageLine['words']:
                        content = word['content']
                        a, b, c, d = word['coord']
                        words.append({'x': a['x'], 'y': a['y'], 'width': b['x'] -a['x'], 'height': d['y'] -a['y'], 'text': content})
                lines.append(words)
        return lines
